﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using TerminationCall.Core;

namespace TerminationCall.Editor.Logic {
    public class PaintTool {

        private EditorTool _editorTool;
        private IPainterFactory _painterFactory;
        private IPainter _painter;

        private Point _lastPaintedPoint;

        private LayerOriginator _layerOriginator;
        private LayerCaretaker _layerCaretaker;
        private List<PaintTile> _paintTiles;
        private LayerMemento _layerMemento;

        public IPainterFactory PainterFactory {
            set {
                _painterFactory = value;
                _painterFactory.EditorTool = _editorTool;
            }
            get {
                return _painterFactory;
            }
        }
        public bool IsPainting { get; set; }

        public PaintTool(EditorTool editorTool) {
            _editorTool = editorTool;
            _layerCaretaker = new LayerCaretaker();
        }

        public void StartPainting(Point point) {
            if (_painterFactory == null) {
                return;
            }

            if (_editorTool.ChoosenTileSet == null) {
                return;
            }

            _paintTiles = new List<PaintTile>();
            _layerOriginator = new LayerOriginator(_editorTool.ChoosenLayer);

            _painter = _painterFactory.CreatePainter(new Point(point.X / TileConstants.TileSizeX, point.Y / TileConstants.TileSizeY));
            _painter.EditorToolManager = new EditorToolManager(_editorTool);

            _lastPaintedPoint = point;

            IsPainting = true;
        }

        public void Paint(Point newPoint) {

            if (_painter == null) {
                return;
            }

            List<Point> points = Bresenham.Line(_lastPaintedPoint, newPoint);

            foreach (Point point in points) {
                _paintTiles.AddRange(_painter.PaintTiles(new Point(point.X / TileConstants.TileSizeX, point.Y / TileConstants.TileSizeY)));
            }

            _layerMemento = _layerOriginator.CreateMemento(_paintTiles.ToArray());
            _lastPaintedPoint = newPoint;
        }

        public void StopPainting() {
            IsPainting = false;

            if ( _layerCaretaker.CurrentMementoIndex < 0 )
            {
                _layerCaretaker.LayerMementos.Clear();
            }
            else if (_layerCaretaker.LayerMementos.Count > 0) {
                if (_layerCaretaker.CurrentMementoIndex + 1 < _layerCaretaker.LayerMementos.Count) {
                    _layerCaretaker.LayerMementos.RemoveRange(_layerCaretaker.CurrentMementoIndex + 1, _layerCaretaker.LayerMementos.Count - _layerCaretaker.CurrentMementoIndex - 1);
                }
            }

            _layerCaretaker.LayerMementos.Add(_layerMemento);
            _layerCaretaker.CurrentMementoIndex = _layerCaretaker.LayerMementos.Count - 1;
        }

        public void CancelPainting() {
            IsPainting = false;
            _layerOriginator.UndoMemento(_layerMemento);
        }

        public void Undo() {

            if (_layerCaretaker.CurrentMementoIndex < 0) {
                return;
            }

            _layerOriginator.UndoMemento(_layerCaretaker.LayerMementos[_layerCaretaker.CurrentMementoIndex]);
            _layerCaretaker.CurrentMementoIndex--;
        }

        public void Redo() {

            if (_layerCaretaker.CurrentMementoIndex + 1 >= _layerCaretaker.LayerMementos.Count) {
                return;
            }

            _layerCaretaker.CurrentMementoIndex++;
            _layerOriginator.RedoMemento(_layerCaretaker.LayerMementos[_layerCaretaker.CurrentMementoIndex]);
        }        
    }
}
